﻿using Microsoft.CodeAnalysis.Scripting;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
using OrBitDataModule.Adaptor;
using OrBitDataModule.Base;
using OrBitDataModule.Common;
using OrBitDataModule.Contract;
using OrBitDataModule.CustomEventHandler;
using OrBitDataModule.Interface;
using OrBitDataModule.Models;
using Quartz;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OrBitDataModule.Protocol
{
    [ProtocolType("定时读取文件夹")]
    public class IntervalFolderWatcher : DataTaskBase
    {
        public IntervalFolderWatcher(string uniqueId, string dataProtocolScriptId, string configJson, string taskName, string taskProtocolType, string apiName, string username, string password)
        {

            this.UniqueId = uniqueId;
            this.TaskName = taskName;
            this.TaskProtocolType = taskProtocolType;
            this.UserName = username;
            this.Password = password;
            this.ApiName = apiName;
            this.ConfigJson = configJson;
            this.DataProtocolScriptId = dataProtocolScriptId;
        }
        ~IntervalFolderWatcher()
        {
            this.OnDispose();
        }
        public override IContext Context { get; set; }
        public override string ConfigJson { get; }
        public override string UniqueId { get; }
        public override string DataProtocolScriptId { get; }
        public override string TaskName { get; }
        public override string UserName { get; }
        public override string Password { get; }
        public override string ApiName { get; }
        public override string Token { get; set; }
        public override int Expiration { get; set; } = 0;
        public override bool IsScripDebug { get; set; } = false;
        public override string ScriptName { get; set; }
        public override string ScriptCode { get; set; }
        public override ScriptRunner ScripterRunner { get; set; }
        public override ScriptBase Script { set; get; }

        public override Encoding DefaultEncoding => StringUtils.GetEncoding(intervalFolder.Encoding);
        public override SerialPort SerialPortInstance { get; set; }
        public override SocketTcpClient TcpClientInstance { get; set; }
        public override string TaskProtocolType { get; }

        private IntervalFolder intervalFolder = null;

        private QuartzScheduler Scheduler = null;

        public override event EventHandler<TaskEventArgs> OnStateChange;

        public override void OnLoad()
        {
            try
            {
                Scheduler = new QuartzScheduler();
                this.ScripterRunner = new ScriptRunner();
                intervalFolder = Newtonsoft.Json.JsonConvert.DeserializeObject<IntervalFolder>(ConfigJson);
                this.SettingProperty = new SettingDictionary(intervalFolder);
            }
            catch (Exception ex)
            {
                Script?.OnError(ex);
                WriteLog(ex.Message);
            }
        }

        /// <summary>
        /// 调度key
        /// </summary>
        private string taskTey = string.Empty;

        public async override void Start()
        {
            try
            {
                OnStateChange?.Invoke(this, new TaskEventArgs(this.UniqueId, TaskRunningStatus.Starting));
                if (!Directory.Exists(intervalFolder.WatchPath))
                {
                    WriteLog($"监控目录不存在，任务已停止!");
                    OnStateChange?.Invoke(this, new TaskEventArgs(this.UniqueId, TaskRunningStatus.Stoped));
                    return;
                }
                //获取最新的脚本代码,开始重新编译一次
                if (!string.IsNullOrWhiteSpace(this.DataProtocolScriptId))
                {
                    var result = await ScriptApi.GetCodeAsync(this.DataProtocolScriptId);
                    this.ScriptName = result.ScriptName;
                    this.ScriptCode = result.ScriptCode;

                    CompileScript();
                    if (!this.CanRunScript)
                    {
                        OnStateChange?.Invoke(this, new TaskEventArgs(this.UniqueId, TaskRunningStatus.Stoped));
                        return;
                    }
                }
                if (string.IsNullOrWhiteSpace(taskTey))
                {
                    Script?.OnLoad();
                    taskTey = await Scheduler.AddTask(TimeSpan.FromSeconds(intervalFolder.ReadFileInterval), new Action(async () =>
                    {
                        await ReadFile();
                    }));
                }

                if (!Scheduler.GetScheduler().IsStarted)
                {
                    Scheduler.Start();
                }
                WriteLog($"任务名称：{TaskName}，任务类型：定时读取文件夹,Api接口：{ApiName},已启动!");
                Script?.OnStarted();
                OnStateChange?.Invoke(this, new TaskEventArgs(this.UniqueId, TaskRunningStatus.Started));
            }
            catch (Exception ex)
            {
                Script?.OnError(ex);
                WriteLog(ex.Message);
                OnStateChange?.Invoke(this, new TaskEventArgs(this.UniqueId, TaskRunningStatus.Stoped));
            }
        }

        /// <summary>
        /// 读取已存在的文件
        /// </summary>
        /// <returns></returns>
        private async Task ReadFile()
        {
            if (ScripterRunner.CanExcute && !string.IsNullOrWhiteSpace(this.DataProtocolScriptId))
            {
                Debug.WriteLine($"TaskName = {this.TaskName}调度执行开始");
                List<string> files = FileUtils.TraverseFolder(intervalFolder.WatchPath, intervalFolder.FileExtensions, intervalFolder.IsWatchSubDir);
                foreach (string file in files)
                {
                    ProcessedFileSystemEventArgs eventArgs = new ProcessedFileSystemEventArgs(WatcherChangeTypes.Created, file, Path.GetFileName(file));
                    await PorcessFile(null, eventArgs);
                }
            }
        }

        /// <summary>
        /// 处理文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        private async Task PorcessFile(object sender, ProcessedFileSystemEventArgs e)
        {
            if (File.Exists(e.FullPath))
            {
                try
                {
                    WriteLog($"文件：{e.FullPath}已{Enum.GetName(typeof(WatcherChangeTypes), e.ChangeType)}");
                    string text = string.Empty;
                    if (string.IsNullOrWhiteSpace(intervalFolder.FileType) || intervalFolder.FileType == "文本")
                    {
                        text = await FileUtils.ReadTextFileAsync(e.FullPath, StringUtils.GetEncoding(intervalFolder.Encoding));
                    }
                    else if (intervalFolder.FileType == "Excel")
                    {
                        text = FileUtils.ReadExcelString(e.FullPath);
                    }
                    else if (intervalFolder.FileType == "CSV")
                    {
                        text = FileUtils.ReadCSVString(e.FullPath, StringUtils.GetEncoding(intervalFolder.Encoding));
                    }

                    ProcessedFileSystemEventArgs eventArgs = e;
                    Script?.OnFileSystem_Changed(sender, eventArgs);
                    string s = eventArgs.Content;
                    string content = Script == null ? text : eventArgs.Content;
                    if (!eventArgs.IsSubmit)
                    {
                        if (string.IsNullOrWhiteSpace(Token))
                        {
                            GetWebApiToken();
                            if (string.IsNullOrWhiteSpace(Token))
                            {
                                WriteLog("接口未能获取到token，请检查", LogLevel.Error);
                                return;
                            }
                        }

                        InputParameter inputParameter = new InputParameter()
                        {
                            TaskName = TaskName,
                            ApiName = ApiName,
                            UserName = UserName,
                            ProtocolType = "监控文件夹",
                            ClientIP = NetworkUtils.GetLocalIPAddresses(),
                            ClientMAC = NetworkUtils.GetLocalMACAddress(),
                            ClientHostName = NetworkUtils.GetComputerName(),
                            Parameter1 = JsonConvert.SerializeObject(LocalSetting.GetConfig(this.UniqueId).parameters),
                            Parameter2 = e.FullPath
                        };
                        Script?.BeforeSubmit(inputParameter, content);
                        var result = await WebApi.IntegrationApiPostAsync(ApiName, Token, inputParameter, content);
                        WriteLog($"文件：{e.FullPath}，已提交至接口：{ApiName},返回:{result.Result},信息:{result.ReturnMessage}", LogLevel.Info);
                        Script?.AfterSubmit(result.Result, result.ReturnMessage, result.OutputResponse);
                    }
                    if (!string.IsNullOrWhiteSpace(intervalFolder.BackupFilePath))
                    {
                        if (eventArgs.IsMoveToBackupDirectory)
                        {
                            string dstFileName = FileUtils.MoveFile(e.FullPath, intervalFolder.BackupFilePath);
                            WriteLog($"文件：{e.FullPath}已移动到备份目录:{dstFileName}", LogLevel.Info);
                        }
                    }
                }
                catch (Exception ex)
                {
                    WriteLog($"Api接口：{ApiName},提交数据出现异常！信息:{ex.Message}");
                }
            }
        }

        public override void Stop()
        {
            try
            {
                OnStateChange?.Invoke(this, new TaskEventArgs(this.UniqueId, TaskRunningStatus.Stopping));
                Scheduler.Start();
                WriteLog($"任务名称：{TaskName}，任务类型：定时读取文件夹,Api接口：{ApiName},已停止!");
                Script?.OnStoped();
                OnStateChange?.Invoke(this, new TaskEventArgs(this.UniqueId, TaskRunningStatus.Stoped));
            }
            catch (Exception ex)
            {
                Script?.OnError(ex);
                WriteLog(ex.Message);
            }
        }
        public override string SendExternal(string message) => string.Empty;
        public override void OnDispose()
        {
            if (Scheduler == null)
            {
                return;
            }
            Scheduler?.Shutdown();
            intervalFolder = null;
            Script?.OnDispose();
        }
    }
}
